home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / lwlib / lwlib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-28  |  30.5 KB  |  1,293 lines

  1. /* A general interface to the widgets of different toolkits.
  2.    Copyright (C) 1992, 1993, 1994 Lucid, Inc.
  3.    Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
  4.  
  5. This file is part of the Lucid Widget Library.
  6.  
  7. The Lucid Widget Library is free software; you can redistribute it and/or 
  8. modify it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2, or (at your option)
  10. any later version.
  11.  
  12. The Lucid Widget Library is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU Emacs; see the file COPYING.  If not, write to
  19. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. #ifdef NeXT
  22. #undef __STRICT_BSD__ /* ick */
  23. #endif
  24.  
  25. #include <stdlib.h>
  26. #include <unistd.h>
  27. #include <sys/types.h>
  28. #include <string.h>
  29. #include <stdio.h>
  30. #include <X11/StringDefs.h>
  31. #include "lwlib-internal.h"
  32. #include "lwlib-utils.h"
  33.  
  34. #if defined(__GNUC__) && !defined(alloca)
  35. #define alloca __builtin_alloca
  36. #endif
  37.  
  38. #if ((!__GNUC__) && !defined(__hpux)) && !defined(_AIX) && !defined (_SCO_DS)
  39. #include <alloca.h>
  40. #endif
  41.  
  42. #ifdef __SUNPRO_C
  43. void *__builtin_alloca (unsigned int);
  44. #endif
  45.  
  46. #if defined(_AIX)
  47. #pragma alloca
  48. #endif
  49.  
  50. #ifdef BROKEN_SUNOS_HEADERS
  51. extern void *    memset (void *, int, int);
  52. extern int    strcasecmp (char *, char *);
  53. extern int      fprintf (FILE *, CONST char *, ...);
  54. #endif
  55.  
  56. #ifdef NEED_LUCID
  57. #include "lwlib-Xlw.h"
  58. #endif
  59. #ifdef NEED_MOTIF
  60. #include "lwlib-Xm.h"
  61. #endif
  62. #ifdef NEED_ATHENA
  63. #include "lwlib-Xaw.h"
  64. #endif
  65.  
  66. /* #### Does a check need to be put back in here to make sure we have
  67.    sufficient defines to function properly or are the checks in the
  68.    makefile sufficient? */
  69.  
  70. /* List of all widgets managed by the library.  Note that each "widget"
  71.    listed here may actually be a tree of widgets; for example, a
  72.    single entry here might represent a single menubar or popup menu,
  73.    each of which might be implemented with a tree of widgets.
  74.    */
  75. static widget_info *all_widget_info = NULL;
  76.  
  77.  
  78. /* Forward declarations */
  79. static void
  80. instantiate_widget_instance (widget_instance *instance);
  81.  
  82.  
  83. /* utility functions for widget_instance and widget_info */
  84. static char *
  85. safe_strdup (CONST char *s)
  86. {
  87.   char *result;
  88.   if (! s) return 0;
  89.   result = (char *) malloc (strlen (s) + 1);
  90.   if (! result)
  91.     return 0;
  92.   strcpy (result, s);
  93.   return result;
  94. }
  95.  
  96. static void
  97. safe_free_str (char *s)
  98. {
  99.   if (s) free (s);
  100. }
  101.  
  102. static widget_value *widget_value_free_list = 0;
  103.  
  104. widget_value *
  105. malloc_widget_value (void)
  106. {
  107.   widget_value *wv;
  108.   if (widget_value_free_list)
  109.     {
  110.       wv = widget_value_free_list;
  111.       widget_value_free_list = wv->free_list;
  112.       wv->free_list = 0;
  113.     }
  114.   else
  115.     {
  116.       wv = (widget_value *) malloc (sizeof (widget_value));
  117.     }
  118.   if (wv)
  119.     {
  120.       memset (wv, 0, sizeof (widget_value));
  121.     }
  122.   return wv;
  123. }
  124.  
  125. /* this is analogous to free().  It frees only what was allocated
  126.    by malloc_widget_value(), and no substructures. 
  127.  */
  128. void
  129. free_widget_value (widget_value *wv)
  130. {
  131.   if (wv->free_list)
  132.     abort ();
  133.   wv->free_list = widget_value_free_list;
  134.   widget_value_free_list = wv;
  135. }
  136.  
  137. static void free_widget_value_tree (widget_value *wv);
  138.  
  139. static void
  140. free_widget_value_contents (widget_value *wv)
  141. {
  142.   if (wv->name) free (wv->name);
  143.   if (wv->value) free (wv->value);
  144.   if (wv->key) free (wv->key);
  145.  
  146.   /* #### - all of this 0xDEADBEEF stuff should be unnecessary
  147.      in production code...  it should be conditionalized. */
  148.   wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
  149.  
  150.   if (wv->toolkit_data && wv->free_toolkit_data)
  151.     {
  152.       free (wv->toolkit_data);
  153.       wv->toolkit_data = (void *) 0xDEADBEEF;
  154.     }
  155.   if (wv->scrollbar_data)
  156.     {
  157.       free (wv->scrollbar_data);
  158.       wv->scrollbar_data = NULL;
  159.     }
  160.   if (wv->contents && (wv->contents != (widget_value*)1))
  161.     {
  162.       free_widget_value_tree (wv->contents);
  163.       wv->contents = (widget_value *) 0xDEADBEEF;
  164.     }
  165.   if (wv->next)
  166.     {
  167.       free_widget_value_tree (wv->next);
  168.       wv->next = (widget_value *) 0xDEADBEEF;
  169.     }
  170. }
  171.  
  172. static void
  173. free_widget_value_tree (widget_value *wv)
  174. {
  175.   if (!wv)
  176.     return;
  177.  
  178.   free_widget_value_contents (wv);
  179.   free_widget_value (wv);
  180. }
  181.  
  182. static void
  183. copy_scrollbar_values (widget_value *val, widget_value *copy)
  184. {
  185.   if (!copy->scrollbar_data)
  186.     copy->scrollbar_data =
  187.       (scrollbar_values *) malloc (sizeof (scrollbar_values));
  188.  
  189.   if (val->scrollbar_data)
  190.     *copy->scrollbar_data = *val->scrollbar_data;
  191.   else
  192.     memset (copy->scrollbar_data, 0, sizeof (scrollbar_values));
  193. }
  194.  
  195. /*
  196.  * Return true if old->scrollbar_data were not equivalent
  197.  * to new->scrollbar_data.
  198.  */
  199. static Boolean
  200. merge_scrollbar_values (widget_value *old, widget_value *new)
  201. {
  202.   Boolean changed = False;
  203.  
  204.   if (new->scrollbar_data && !old->scrollbar_data)
  205.     {
  206.       copy_scrollbar_values (new, old);
  207.       changed = True;
  208.     }
  209.   else if (!new->scrollbar_data && old->scrollbar_data)
  210.     {
  211.       free (old->scrollbar_data);
  212.       old->scrollbar_data = NULL;
  213.     }
  214.   else if (new->scrollbar_data && old->scrollbar_data)
  215.     {
  216.       scrollbar_values *old_sb = old->scrollbar_data;
  217.       scrollbar_values *new_sb = new->scrollbar_data;
  218. #define FROB(field) if (old_sb->field != new_sb->field) changed = True
  219.       FROB (line_increment);
  220.       FROB (page_increment);
  221.       FROB (minimum);
  222.       FROB (maximum);
  223.       FROB (slider_size);
  224.       FROB (slider_position);
  225.       FROB (scrollbar_width);
  226.       FROB (scrollbar_height);
  227.       FROB (scrollbar_x);
  228.       FROB (scrollbar_y);
  229. #undef FROB
  230.       *old_sb = *new_sb;
  231.     }
  232.  
  233.   return changed;
  234. }
  235.  
  236. /* Make a complete copy of a widget_value tree.  Store CHANGE into
  237.    the widget_value tree's `change' field. */
  238.  
  239. static widget_value *
  240. copy_widget_value_tree (widget_value *val, change_type change)
  241. {
  242.   widget_value *copy;
  243.   
  244.   if (!val)
  245.     return NULL;
  246.   if (val == (widget_value *) 1)
  247.     return val;
  248.  
  249.   copy = malloc_widget_value ();
  250.   if (copy)
  251.     {
  252.       /* #### - don't seg fault *here* if out of memory.  Menus will be
  253.      truncated inexplicably. */
  254.       copy->type = val->type;
  255.       copy->name = safe_strdup (val->name);
  256.       copy->value = safe_strdup (val->value);
  257.       copy->key = safe_strdup (val->key);
  258.       copy->enabled = val->enabled;
  259.       copy->selected = val->selected;
  260.       copy->edited = False;
  261.       copy->change = change;
  262.       copy->contents = copy_widget_value_tree (val->contents, change);
  263.       copy->call_data = val->call_data;
  264.       copy->next = copy_widget_value_tree (val->next, change);
  265.       copy->toolkit_data = NULL;
  266.       copy->free_toolkit_data = False;
  267.       copy_scrollbar_values (val, copy);
  268.     }
  269.   return copy;
  270. }
  271.  
  272. /* This function is used to implement incremental menu construction. */
  273.  
  274. widget_value *
  275. replace_widget_value_tree (widget_value *node, widget_value *newtree)
  276. {
  277.   widget_value *copy;
  278.  
  279.   if (!node || !newtree)
  280.     abort ();
  281.  
  282.   copy = copy_widget_value_tree (newtree, STRUCTURAL_CHANGE);
  283.  
  284.   free_widget_value_contents (node);
  285.   *node = *copy;
  286.   free_widget_value (copy);    /* free the node, but not its contents. */
  287.   return node;
  288. }
  289.  
  290. static widget_info *
  291. allocate_widget_info (CONST char *type, CONST char *name,
  292.                       LWLIB_ID id, widget_value *val,
  293.               lw_callback pre_activate_cb, lw_callback selection_cb,
  294.               lw_callback post_activate_cb)
  295. {
  296.   widget_info *info = (widget_info *) malloc (sizeof (widget_info));
  297.   info->type = safe_strdup (type);
  298.   info->name = safe_strdup (name);
  299.   info->id = id;
  300.   info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
  301.   info->busy = False;
  302.   info->pre_activate_cb = pre_activate_cb;
  303.   info->selection_cb = selection_cb;
  304.   info->post_activate_cb = post_activate_cb;
  305.   info->instances = NULL;
  306.  
  307.   info->next = all_widget_info;
  308.   all_widget_info = info;
  309.  
  310.   return info;
  311. }
  312.  
  313. static void
  314. free_widget_info (widget_info *info)
  315. {
  316.   safe_free_str (info->type);
  317.   safe_free_str (info->name);
  318.   free_widget_value_tree (info->val);
  319.   memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
  320.   free (info);
  321. }
  322.  
  323. static void
  324. mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
  325. {
  326.   widget_instance *instance = (widget_instance*)closure;
  327.  
  328.   /* be very conservative */
  329.   if (instance->widget == widget)
  330.     instance->widget = NULL;
  331. }
  332.  
  333. static widget_instance *
  334. allocate_widget_instance (widget_info *info, Widget parent, Boolean pop_up_p)
  335. {
  336.   widget_instance *instance =
  337.     (widget_instance *) malloc (sizeof (widget_instance));
  338.   instance->parent = parent;
  339.   instance->pop_up_p = pop_up_p;
  340.   instance->info = info;
  341.   instance->next = info->instances;
  342.   info->instances = instance;
  343.  
  344.   instantiate_widget_instance (instance);
  345.  
  346.   XtAddCallback (instance->widget, XtNdestroyCallback,
  347.          mark_widget_destroyed, (XtPointer)instance);
  348.   return instance;
  349. }
  350.  
  351. static void
  352. free_widget_instance (widget_instance *instance)
  353. {
  354.   memset ((void *) instance, 0xDEADBEEF, sizeof (widget_instance));
  355.   free (instance);
  356. }
  357.  
  358. static widget_info *
  359. get_widget_info (LWLIB_ID id, Boolean remove_p)
  360. {
  361.   widget_info *info;
  362.   widget_info *prev;
  363.   for (prev = NULL, info = all_widget_info;
  364.        info;
  365.        prev = info, info = info->next)
  366.     if (info->id == id)
  367.      {
  368.        if (remove_p)
  369.      {
  370.        if (prev)
  371.          prev->next = info->next;
  372.        else
  373.          all_widget_info = info->next;
  374.      }
  375.       return info;
  376.      }
  377.   return NULL;
  378. }
  379.  
  380. /* Internal function used by the library dependent implementation to get the
  381.    widget_value for a given widget in an instance */
  382. widget_info *
  383. lw_get_widget_info (LWLIB_ID id)
  384. {
  385.   return get_widget_info (id, 0);
  386. }
  387.  
  388. static int
  389. map_widget_values (widget_value *value, int (*mapfunc) (widget_value *value,
  390.                             void *closure),
  391.            void *closure)
  392. {
  393.   int retval = 0;
  394.  
  395.   if (value->contents)
  396.     retval = map_widget_values (value->contents, mapfunc, closure);
  397.   if (retval)
  398.     return retval;
  399.  
  400.   if (value->next)
  401.     retval = map_widget_values (value->next, mapfunc, closure);
  402.   if (retval)
  403.     return retval;
  404.  
  405.   return (mapfunc) (value, closure);
  406. }
  407.  
  408. int
  409. lw_map_widget_values (LWLIB_ID id, int (*mapfunc) (widget_value *value,
  410.                            void *closure),
  411.               void *closure)
  412. {
  413.   widget_info *info = get_widget_info (id, 0);
  414.  
  415.   if (!info)
  416.     abort ();
  417.  
  418.   if (info->val)
  419.     return map_widget_values (info->val, mapfunc, closure);
  420.   return 0;
  421. }
  422.  
  423. static widget_instance *
  424. get_widget_instance (Widget widget, Boolean remove_p)
  425. {
  426.   widget_info *info;
  427.   widget_instance *instance;
  428.   widget_instance *prev;
  429.   for (info = all_widget_info; info; info = info->next)
  430.     for (prev = NULL, instance = info->instances;
  431.      instance;
  432.      prev = instance, instance = instance->next)
  433.       if (instance->widget == widget)
  434.     {
  435.       if (remove_p)
  436.         {
  437.           if (prev)
  438.         prev->next = instance->next;
  439.           else
  440.         info->instances = instance->next;
  441.         }
  442.       return instance;
  443.     }
  444.   return (widget_instance *) 0;
  445. }
  446.  
  447. static widget_instance*
  448. find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
  449. {
  450.   widget_info *info = get_widget_info (id, False);
  451.   widget_instance *instance;
  452.  
  453.   if (info)
  454.     for (instance = info->instances; instance; instance = instance->next)
  455.       if (instance->parent == parent && instance->pop_up_p == pop_up_p)
  456.     return instance;
  457.  
  458.   return NULL;
  459. }
  460.  
  461.  
  462. /* utility function for widget_value */
  463. static Boolean
  464. safe_strcmp (CONST char *s1, CONST char *s2)
  465. {
  466.   if (!!s1 ^ !!s2) return True;
  467.   return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
  468. }
  469.  
  470. static int
  471. max (int i1, int i2)
  472. {
  473.   return i1 > i2 ? i1 : i2;
  474. }
  475.  
  476.  
  477. #if 0
  478. # define EXPLAIN(name, oc, nc, desc, a1, a2)                \
  479.    printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n",        \
  480.        name,                            \
  481.        (oc == NO_CHANGE ? "none" :                    \
  482.         (oc == INVISIBLE_CHANGE ? "invisible" :            \
  483.          (oc == VISIBLE_CHANGE ? "visible" :            \
  484.           (oc == STRUCTURAL_CHANGE ? "structural" : "???")))),    \
  485.        oc,                                \
  486.        (nc == NO_CHANGE ? "none" :                    \
  487.         (nc == INVISIBLE_CHANGE ? "invisible" :            \
  488.          (nc == VISIBLE_CHANGE ? "visible" :            \
  489.           (nc == STRUCTURAL_CHANGE ? "structural" : "???")))),    \
  490.        nc, desc, a1, a2)
  491. #else
  492. # define EXPLAIN(name, oc, nc, desc, a1, a2)
  493. #endif
  494.  
  495.  
  496. static widget_value *
  497. merge_widget_value (widget_value *val1, widget_value *val2, int level)
  498. {
  499.   change_type change;
  500.   widget_value *merged_next;
  501.   widget_value *merged_contents;
  502.  
  503.   if (!val1)
  504.     {
  505.       if (val2)
  506.     return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
  507.       else
  508.     return NULL;
  509.     }
  510.   if (!val2)
  511.     {
  512.       free_widget_value_tree (val1);
  513.       return NULL;
  514.     }
  515.   
  516.   change = NO_CHANGE;
  517.  
  518.   if (val1->type != val2->type)
  519.     {
  520.       EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "type change",
  521.            val1->type, val2->type);
  522.       change = max (change, STRUCTURAL_CHANGE);
  523.       val1->type = val2->type;
  524.     }
  525.   if (safe_strcmp (val1->name, val2->name))
  526.     {
  527.       EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
  528.            val1->name, val2->name);
  529.       change = max (change, STRUCTURAL_CHANGE);
  530.       safe_free_str (val1->name);
  531.       val1->name = safe_strdup (val2->name);
  532.     }
  533.   if (safe_strcmp (val1->value, val2->value))
  534.     {
  535.       EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
  536.            val1->value, val2->value);
  537.       change = max (change, VISIBLE_CHANGE);
  538.       safe_free_str (val1->value);
  539.       val1->value = safe_strdup (val2->value);
  540.     }
  541.   if (safe_strcmp (val1->key, val2->key))
  542.     {
  543.       EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
  544.            val1->key, val2->key);
  545.       change = max (change, VISIBLE_CHANGE);
  546.       safe_free_str (val1->key);
  547.       val1->key = safe_strdup (val2->key);
  548.     }
  549.   if (val1->enabled != val2->enabled)
  550.     {
  551.       EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
  552.            val1->enabled, val2->enabled);
  553.       change = max (change, VISIBLE_CHANGE);
  554.       val1->enabled = val2->enabled;
  555.     }
  556.   if (val1->selected != val2->selected)
  557.     {
  558.       EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
  559.            val1->selected, val2->selected);
  560.       change = max (change, VISIBLE_CHANGE);
  561.       val1->selected = val2->selected;
  562.     }
  563.   if (val1->call_data != val2->call_data)
  564.     {
  565.       EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
  566.            val1->call_data, val2->call_data);
  567.       change = max (change, INVISIBLE_CHANGE);
  568.       val1->call_data = val2->call_data;
  569.     }
  570.   if (merge_scrollbar_values (val1, val2))
  571.     {
  572.       EXPLAIN (val1->name, change, VISIBLE_CHANGE, "scrollbar change", 0, 0);
  573.       change = max (change, VISIBLE_CHANGE);
  574.     }
  575.  
  576.   if (level > 0)
  577.     {
  578.       merged_contents =
  579.     merge_widget_value (val1->contents, val2->contents, level - 1);
  580.       
  581.       if (val1->contents && !merged_contents)
  582.     {
  583.       EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents gone)",
  584.            0, 0);
  585.       change = max (change, INVISIBLE_CHANGE);
  586.     }
  587.       else if (merged_contents && merged_contents->change != NO_CHANGE)
  588.     {
  589.       EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
  590.            0, 0);
  591.       change = max (change, INVISIBLE_CHANGE);
  592.     }
  593.       
  594.       val1->contents = merged_contents;
  595.     }
  596.  
  597.   merged_next = merge_widget_value (val1->next, val2->next, level);
  598.  
  599.   if (val1->next && !merged_next)
  600.     {
  601.       EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
  602.            0, 0);
  603.       change = max (change, STRUCTURAL_CHANGE);
  604.     }
  605.   else if (merged_next)
  606.     {
  607.       if (merged_next->change)
  608.       {
  609.     EXPLAIN (val1->name, change, merged_next->change, "(following change)",
  610.          0, 0);
  611.       }
  612.       change = max (change, merged_next->change);
  613.     }
  614.  
  615.   val1->next = merged_next;
  616.  
  617.   val1->change = change;
  618.   
  619.   if (change > NO_CHANGE && val1->toolkit_data)
  620.     {
  621.       if (val1->free_toolkit_data)
  622.     free (val1->toolkit_data);
  623.       val1->toolkit_data = NULL;
  624.     }
  625.  
  626.   return val1;
  627. }
  628.  
  629.  
  630. /* modifying the widgets */
  631. static Widget
  632. name_to_widget (widget_instance *instance, CONST char *name)
  633. {
  634.   Widget widget = NULL;
  635.  
  636.   if (!instance->widget)
  637.     return NULL;
  638.  
  639.   if (!strcmp (XtName (instance->widget), name))
  640.     widget = instance->widget;
  641.   else
  642.     {
  643.       int length = strlen (name) + 2;
  644.       char *real_name = (char *) alloca (length);
  645.       real_name [0] = '*';
  646.       strcpy (real_name + 1, name);
  647.       
  648.       widget = XtNameToWidget (instance->widget, real_name);
  649.     }
  650.   return widget;
  651. }
  652.  
  653. static void
  654. set_one_value (widget_instance *instance, widget_value *val, Boolean deep_p)
  655. {
  656.   Widget widget = name_to_widget (instance, val->name);
  657.   
  658.   if (widget)
  659.     {
  660. #ifdef NEED_LUCID
  661.       if (lw_lucid_widget_p (instance->widget))
  662.     xlw_update_one_widget (instance, widget, val, deep_p);
  663. #endif
  664. #ifdef NEED_MOTIF
  665.       if (lw_motif_widget_p (instance->widget))
  666.     xm_update_one_widget (instance, widget, val, deep_p);
  667. #endif
  668. #ifdef NEED_ATHENA
  669.       if (lw_xaw_widget_p (instance->widget))
  670.     xaw_update_one_widget (instance, widget, val, deep_p);
  671. #endif
  672.     }
  673. }
  674.  
  675. static void
  676. update_one_widget_instance (widget_instance *instance, Boolean deep_p)
  677. {
  678.   widget_value *val;
  679.  
  680.   if (!instance->widget)
  681.     /* the widget was destroyed */
  682.     return;
  683.  
  684.   for (val = instance->info->val; val; val = val->next)
  685.     if (val->change != NO_CHANGE)
  686.       set_one_value (instance, val, deep_p);
  687. }
  688.  
  689. static void
  690. update_all_widget_values (widget_info *info, Boolean deep_p)
  691. {
  692.   widget_instance *instance;
  693.   widget_value *val;
  694.  
  695.   for (instance = info->instances; instance; instance = instance->next)
  696.     update_one_widget_instance (instance, deep_p);
  697.  
  698.   for (val = info->val; val; val = val->next)
  699.     val->change = NO_CHANGE;
  700. }
  701.  
  702. void
  703. lw_modify_all_widgets (LWLIB_ID id, widget_value *val, Boolean deep_p)
  704. {
  705.   widget_info *info = get_widget_info (id, False);
  706.   widget_value *new_val;
  707.   widget_value *next_new_val;
  708.   widget_value *cur;
  709.   widget_value *prev;
  710.   widget_value *next;
  711.   int        found;
  712.  
  713.   if (!info)
  714.     return;
  715.  
  716.   for (new_val = val; new_val; new_val = new_val->next)
  717.     {
  718.       next_new_val = new_val->next;
  719.       new_val->next = NULL;
  720.       found = False;
  721.       for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
  722.     if (!strcmp (cur->name, new_val->name))
  723.       {
  724.         found = True;
  725.         next = cur->next;
  726.         cur->next = NULL;
  727.         cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1);
  728.         if (prev)
  729.           prev->next = cur ? cur : next;
  730.         else
  731.           info->val = cur ? cur : next;
  732.         if (cur)
  733.           cur->next = next;
  734.         break;
  735.       }
  736.       if (!found)
  737.     {
  738.       /* Could not find it, add it */
  739.       if (prev)
  740.         prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
  741.       else
  742.         info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
  743.     }
  744.       new_val->next = next_new_val;
  745.     }
  746.  
  747.   update_all_widget_values (info, deep_p);
  748. }
  749.  
  750.  
  751. /* creating the widgets */
  752.  
  753. static void
  754. initialize_widget_instance (widget_instance *instance)
  755. {
  756.   widget_value *val;
  757.  
  758.   for (val = instance->info->val; val; val = val->next)
  759.     val->change = STRUCTURAL_CHANGE;
  760.  
  761.   update_one_widget_instance (instance, True);
  762.  
  763.   for (val = instance->info->val; val; val = val->next)
  764.     val->change = NO_CHANGE;
  765. }
  766.  
  767.  
  768. static widget_creation_function
  769. find_in_table (CONST char *type, widget_creation_entry *table)
  770. {
  771.   widget_creation_entry *cur;
  772.   for (cur = table; cur->type; cur++)
  773.     if (!strcasecmp (type, cur->type))
  774.       return cur->function;
  775.   return NULL;
  776. }
  777.  
  778. static Boolean
  779. dialog_spec_p (CONST char *name)
  780. {
  781.   /* return True if name matches [EILPQeilpq][1-9][Bb] or 
  782.      [EILPQeilpq][1-9][Bb][Rr][1-9] */
  783.   if (!name)
  784.     return False;
  785.   
  786.   switch (name [0])
  787.     {
  788.     case 'E': case 'I': case 'L': case 'P': case 'Q':
  789.     case 'e': case 'i': case 'l': case 'p': case 'q':
  790.       if (name [1] >= '0' && name [1] <= '9')
  791.     {
  792.       if (name [2] != 'B' && name [2] != 'b')
  793.         return False;
  794.       if (!name [3])
  795.         return True;
  796.       if ((name [3] == 'T' || name [3] == 't') && !name [4])
  797.         return True;
  798.       if ((name [3] == 'R' || name [3] == 'r')
  799.           && name [4] >= '0' && name [4] <= '9' && !name [5])
  800.         return True;
  801.       return False;
  802.     }
  803.       else
  804.     return False;
  805.     
  806.     default:
  807.       return False;
  808.     }
  809. }
  810.  
  811. static void
  812. instantiate_widget_instance (widget_instance *instance)
  813. {
  814.   widget_creation_function function = NULL;
  815.  
  816. #ifdef NEED_LUCID
  817.   if (!function)
  818.     function = find_in_table (instance->info->type, xlw_creation_table);
  819. #endif
  820. #ifdef NEED_MOTIF
  821.   if (!function)
  822.     function = find_in_table (instance->info->type, xm_creation_table);
  823. #endif
  824. #ifdef NEED_ATHENA
  825.   if (!function)
  826.     function = find_in_table (instance->info->type, xaw_creation_table);
  827. #endif
  828.  
  829.   if (!function)
  830.     {
  831.       if (dialog_spec_p (instance->info->type))
  832.     {
  833. #ifdef DIALOGS_MOTIF
  834.       if (!function)
  835.         function = xm_create_dialog;
  836. #endif
  837. #ifdef DIALOGS_ATHENA
  838.       if (!function)
  839.         function = xaw_create_dialog;
  840. #endif
  841. #ifdef DIALOGS_LUCID
  842.       /* not yet (not ever?) */
  843. #endif
  844.     }
  845.     }
  846.   
  847.   if (!function)
  848.     {
  849.       fprintf (stderr, "No creation function for widget type %s\n",
  850.            instance->info->type);
  851.       abort ();
  852.     }
  853.  
  854.   instance->widget = (*function) (instance);
  855.  
  856.   if (!instance->widget)
  857.     abort ();
  858.  
  859.   /*   XtRealizeWidget (instance->widget);*/
  860. }
  861.  
  862. void 
  863. lw_register_widget (CONST char *type, CONST char *name,
  864.                     LWLIB_ID id, widget_value *val,
  865.             lw_callback pre_activate_cb, lw_callback selection_cb,
  866.             lw_callback post_activate_cb)
  867. {
  868.   if (!get_widget_info (id, False))
  869.     allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
  870.               post_activate_cb);
  871. }
  872.  
  873. Widget
  874. lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
  875. {
  876.   widget_instance *instance;
  877.   
  878.   instance = find_instance (id, parent, pop_up_p);
  879.   return instance ? instance->widget : NULL;
  880. }
  881.  
  882. Widget
  883. lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
  884. {
  885.   widget_instance *instance;
  886.   widget_info *info;
  887.   
  888.   instance = find_instance (id, parent, pop_up_p);
  889.   if (!instance)
  890.     {
  891.       info = get_widget_info (id, False);
  892.       if (!info)
  893.     return NULL;
  894.       instance = allocate_widget_instance (info, parent, pop_up_p);
  895.       initialize_widget_instance (instance);
  896.     }
  897.   if (!instance->widget)
  898.     abort ();
  899.   return instance->widget;
  900. }
  901.  
  902. Widget
  903. lw_create_widget (CONST char *type, CONST char *name,
  904.                   LWLIB_ID id, widget_value *val,
  905.           Widget parent, Boolean pop_up_p, lw_callback pre_activate_cb,
  906.           lw_callback selection_cb, lw_callback post_activate_cb)
  907. {
  908.   lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
  909.               post_activate_cb);
  910.   return lw_make_widget (id, parent, pop_up_p);
  911. }
  912.           
  913.  
  914. /* destroying the widgets */
  915. static void
  916. destroy_one_instance (widget_instance *instance)
  917. {
  918.   /* Remove the destroy callback on the widget; that callback will try to
  919.      dereference the instance object (to set its widget slot to 0, since the
  920.      widget is dead.)  Since the instance is now dead, we don't have to worry
  921.      about the fact that its widget is dead too.
  922.  
  923.      This happens in the Phase2Destroy of the widget, so this callback would
  924.      not have been run until arbitrarily long after the instance was freed.
  925.    */
  926.   if (instance->widget)
  927.     XtRemoveCallback (instance->widget, XtNdestroyCallback,
  928.               mark_widget_destroyed, (XtPointer)instance);
  929.  
  930.   if (instance->widget)
  931.     {
  932.       /* The else are pretty tricky here, including the empty statement
  933.      at the end because it would be very bad to destroy a widget
  934.      twice. */
  935. #ifdef NEED_LUCID
  936.       if (lw_lucid_widget_p (instance->widget))
  937.     xlw_destroy_instance (instance);
  938.       else
  939. #endif
  940. #ifdef NEED_MOTIF
  941.       if (lw_motif_widget_p (instance->widget))
  942.     xm_destroy_instance (instance);
  943.       else
  944. #endif
  945. #ifdef NEED_ATHENA
  946.       if (lw_xaw_widget_p (instance->widget))
  947.     xaw_destroy_instance (instance);
  948.       else
  949. #endif
  950.         {
  951.           /* do not remove the empty statement */
  952.           ;
  953.         }
  954.     }
  955.  
  956.   free_widget_instance (instance);
  957. }
  958.  
  959. void
  960. lw_destroy_widget (Widget w)
  961. {
  962.   widget_instance *instance = get_widget_instance (w, True);
  963.   
  964.   if (instance)
  965.     {
  966.       widget_info *info = instance->info;
  967.       /* instance has already been removed from the list; free it */
  968.       destroy_one_instance (instance);
  969.       /* if there are no instances left, free the info too */
  970.       if (!info->instances)
  971.     lw_destroy_all_widgets (info->id);
  972.     }
  973. }
  974.  
  975. void
  976. lw_destroy_all_widgets (LWLIB_ID id)
  977. {
  978.   widget_info *info = get_widget_info (id, True);
  979.   widget_instance *instance;
  980.   widget_instance *next;
  981.  
  982.   if (info)
  983.     {
  984.       for (instance = info->instances; instance; )
  985.     {
  986.       next = instance->next;
  987.       destroy_one_instance (instance);
  988.       instance = next;
  989.     }
  990.       free_widget_info (info);
  991.     }
  992. }
  993.  
  994. void
  995. lw_destroy_everything ()
  996. {
  997.   while (all_widget_info)
  998.     lw_destroy_all_widgets (all_widget_info->id);
  999. }
  1000.  
  1001. void
  1002. lw_destroy_all_pop_ups ()
  1003. {
  1004.   widget_info *info;
  1005.   widget_info *next;
  1006.   widget_instance *instance;
  1007.  
  1008.   for (info = all_widget_info; info; info = next)
  1009.     {
  1010.       next = info->next;
  1011.       instance = info->instances;
  1012.       if (instance && instance->pop_up_p)
  1013.     lw_destroy_all_widgets (info->id);
  1014.     }
  1015. }
  1016.  
  1017. Widget
  1018. lw_raise_all_pop_up_widgets (void)
  1019. {
  1020.   widget_info *info;
  1021.   widget_instance *instance;
  1022.   Widget result = NULL;
  1023.  
  1024.   for (info = all_widget_info; info; info = info->next)
  1025.     for (instance = info->instances; instance; instance = instance->next)
  1026.       if (instance->pop_up_p)
  1027.     {
  1028.       Widget widget = instance->widget;
  1029.       if (widget)
  1030.         {
  1031.           if (XtIsManaged (widget)
  1032. #ifdef NEED_MOTIF
  1033.           /* What a complete load of crap!!!!
  1034.              When a dialogShell is on the screen, it is not managed!
  1035.            */
  1036.           || (lw_motif_widget_p (instance->widget) &&
  1037.               XtIsManaged (first_child (widget)))
  1038. #endif
  1039.           )
  1040.         {
  1041.           if (!result)
  1042.             result = widget;
  1043.           XMapRaised (XtDisplay (widget), XtWindow (widget));
  1044.         }
  1045.         }
  1046.     }
  1047.   return result;
  1048. }
  1049.  
  1050. static void
  1051. lw_pop_all_widgets (LWLIB_ID id, Boolean up)
  1052. {
  1053.   widget_info *info = get_widget_info (id, False);
  1054.   widget_instance *instance;
  1055.  
  1056.   if (info)
  1057.     for (instance = info->instances; instance; instance = instance->next)
  1058.       if (instance->pop_up_p && instance->widget)
  1059.     {
  1060. #ifdef NEED_LUCID
  1061.       if (lw_lucid_widget_p (instance->widget))
  1062.         {
  1063.           XtRealizeWidget (instance->widget);
  1064.           xlw_pop_instance (instance, up);
  1065.         }
  1066. #endif
  1067. #ifdef NEED_MOTIF
  1068.       if (lw_motif_widget_p (instance->widget))
  1069.         {
  1070.           XtRealizeWidget (instance->widget);
  1071.           xm_pop_instance (instance, up);
  1072.         }
  1073. #endif
  1074. #ifdef NEED_ATHENA
  1075.       if (lw_xaw_widget_p (instance->widget))
  1076.         {
  1077.           XtRealizeWidget (XtParent (instance->widget));
  1078.           XtRealizeWidget (instance->widget);
  1079.           xaw_pop_instance (instance, up);
  1080.         }
  1081. #endif
  1082.     }
  1083. }
  1084.  
  1085. void
  1086. lw_pop_up_all_widgets (LWLIB_ID id)
  1087. {
  1088.   lw_pop_all_widgets (id, True);
  1089. }
  1090.  
  1091. void
  1092. lw_pop_down_all_widgets (LWLIB_ID id)
  1093. {
  1094.   lw_pop_all_widgets (id, False);
  1095. }
  1096.  
  1097. void
  1098. lw_popup_menu (Widget widget, XEvent *event)
  1099. {
  1100. #ifdef NEED_LUCID
  1101.   if (lw_lucid_widget_p (widget))
  1102.     xlw_popup_menu (widget, event);
  1103. #endif
  1104. #ifdef NEED_MOTIF
  1105.   if (lw_motif_widget_p (widget))
  1106.     xm_popup_menu (widget, event);
  1107. #endif
  1108. #ifdef NEED_ATHENA
  1109.   if (lw_xaw_widget_p (widget))
  1110.     xaw_popup_menu (widget, event); /* not implemented */
  1111. #endif
  1112. }
  1113.  
  1114. /* get the values back */
  1115. static Boolean
  1116. get_one_value (widget_instance *instance, widget_value *val)
  1117. {
  1118.   Widget widget = name_to_widget (instance, val->name);
  1119.       
  1120.   if (widget)
  1121.     {
  1122. #ifdef NEED_LUCID
  1123.       if (lw_lucid_widget_p (instance->widget))
  1124.     xlw_update_one_value (instance, widget, val);
  1125. #endif
  1126. #ifdef NEED_MOTIF
  1127.       if (lw_motif_widget_p (instance->widget))
  1128.     xm_update_one_value (instance, widget, val);
  1129. #endif
  1130. #ifdef NEED_ATHENA
  1131.       if (lw_xaw_widget_p (instance->widget))
  1132.     xaw_update_one_value (instance, widget, val);
  1133. #endif
  1134.       return True;
  1135.     }
  1136.   else
  1137.     return False;
  1138. }
  1139.  
  1140. Boolean
  1141. lw_get_some_values (LWLIB_ID id, widget_value *val_out)
  1142. {
  1143.   widget_info *info = get_widget_info (id, False);
  1144.   widget_instance *instance;
  1145.   widget_value *val;
  1146.   Boolean result = False;
  1147.  
  1148.   if (!info)
  1149.     return False;
  1150.  
  1151.   instance = info->instances;
  1152.   if (!instance)
  1153.     return False;
  1154.  
  1155.   for (val = val_out; val; val = val->next)
  1156.     if (get_one_value (instance, val))
  1157.       result = True;
  1158.  
  1159.   return result;
  1160. }
  1161.  
  1162. widget_value*
  1163. lw_get_all_values (LWLIB_ID id)
  1164. {
  1165.   widget_info *info = get_widget_info (id, False);
  1166.   widget_value *val = info->val;
  1167.   if (lw_get_some_values (id, val))
  1168.     return val;
  1169.   else
  1170.     return NULL;
  1171. }
  1172.  
  1173. /* internal function used by the library dependent implementation to get the
  1174.    widget_value for a given widget in an instance */
  1175. widget_value*
  1176. lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
  1177. {
  1178.   char *name = XtName (w);
  1179.   widget_value *cur;
  1180.   for (cur = instance->info->val; cur; cur = cur->next)
  1181.     if (!strcmp (cur->name, name))
  1182.       return cur;
  1183.   return NULL;
  1184. }
  1185.  
  1186.  
  1187. /* update other instances value when one thing changed */
  1188. /* This function can be used as a an XtCallback for the widgets that get 
  1189.   modified to update other instances of the widgets.  Closure should be the
  1190.   widget_instance. */
  1191. void
  1192. lw_internal_update_other_instances (Widget widget, XtPointer closure,
  1193.                     XtPointer call_data)
  1194. {
  1195.   /* To forbid recursive calls */
  1196.   static Boolean updating;
  1197.   
  1198.   widget_instance *instance = (widget_instance*)closure;
  1199.   char *name = XtName (widget);
  1200.   widget_info *info;
  1201.   widget_instance *cur;
  1202.   widget_value *val;
  1203.  
  1204.   /* never recurse as this could cause infinite recursions. */
  1205.   if (updating)
  1206.     return;
  1207.  
  1208.   /* protect against the widget being destroyed */
  1209.   if (XtWidgetBeingDestroyedP (widget))
  1210.     return;
  1211.  
  1212.   /* Return immediately if there are no other instances */
  1213.   info = instance->info;
  1214.   if (!info->instances->next)
  1215.     return;
  1216.  
  1217.   updating = True;
  1218.  
  1219.   for (val = info->val; val && strcmp (val->name, name); val = val->next);
  1220.  
  1221.   if (val && get_one_value (instance, val))
  1222.     for (cur = info->instances; cur; cur = cur->next)
  1223.       if (cur != instance)
  1224.     set_one_value (cur, val, True);
  1225.  
  1226.   updating = False;
  1227. }
  1228.  
  1229.  
  1230.  
  1231. /* get the id */
  1232.  
  1233. LWLIB_ID
  1234. lw_get_widget_id (Widget w)
  1235. {
  1236.   widget_instance *instance = get_widget_instance (w, False);
  1237.  
  1238.   return instance ? instance->info->id : 0;
  1239. }
  1240.  
  1241.  
  1242. /* set the keyboard focus */
  1243. void
  1244. lw_set_keyboard_focus (Widget parent, Widget w)
  1245. {
  1246. #ifdef NEED_MOTIF
  1247.   xm_set_keyboard_focus (parent, w);
  1248. #else
  1249.   XtSetKeyboardFocus (parent, w);
  1250. #endif
  1251. }
  1252.  
  1253.  
  1254. /* Show busy */
  1255. static void
  1256. show_one_widget_busy (Widget w, Boolean flag)
  1257. {
  1258.   Pixel foreground = 0;
  1259.   Pixel background = 1;
  1260.   Widget widget_to_invert = XtNameToWidget (w, "*sheet");
  1261.   if (!widget_to_invert)
  1262.     widget_to_invert = w;
  1263.   
  1264.   XtVaGetValues (widget_to_invert,
  1265.          XtNforeground, &foreground,
  1266.          XtNbackground, &background,
  1267.          0);
  1268.   XtVaSetValues (widget_to_invert,
  1269.          XtNforeground, background,
  1270.          XtNbackground, foreground,
  1271.          0);
  1272. }
  1273.  
  1274. void
  1275. lw_show_busy (Widget w, Boolean busy)
  1276. {
  1277.   widget_instance *instance = get_widget_instance (w, False);
  1278.   widget_info *info;
  1279.   widget_instance *next;
  1280.  
  1281.   if (instance)
  1282.     {
  1283.       info = instance->info;
  1284.       if (info->busy != busy)
  1285.     {
  1286.       for (next = info->instances; next; next = next->next)
  1287.         if (next->widget)
  1288.           show_one_widget_busy (next->widget, busy);
  1289.       info->busy = busy;
  1290.     }
  1291.     }
  1292. }
  1293.